using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;

namespace ZFramework.Runtime
{
    public partial class EditorModeResourceMgr : FrameworkManagerBase, IResourceMgr
    {
        private Dictionary<string, Object> _cachedAssets = null;
        private FrameworkLinkedList<LoadAssetInfo> _loadAssetInfos = null;
        private FrameworkLinkedList<LoadSceneInfo> _loadSceneInfos = null;
        private FrameworkLinkedList<UnloadSceneInfo> _unloadSceneInfos = null;
        private float _minLoadDelayTime = 0.1f; //模拟加载延迟
        private float _minLoadRandomDelayTime = 0f; //模拟加载延迟
        private float _maxLoadRandomDelayTime = 0.5f; //模拟加载延迟
        private int _loadAssetCountPerFrame = 5;

        protected override void Awake()
        {
            base.Awake();
            _cachedAssets = new Dictionary<string, Object>();
            _loadAssetInfos = new FrameworkLinkedList<LoadAssetInfo>();
            _loadSceneInfos = new FrameworkLinkedList<LoadSceneInfo>();
            _unloadSceneInfos = new FrameworkLinkedList<UnloadSceneInfo>();
        }

        public override void Shutdown()
        {
            _cachedAssets.Clear();
            _loadSceneInfos.Clear();
            _unloadSceneInfos.Clear();
            _loadAssetInfos.Clear();
        }

        public override void OnUpdate(float elapseSeconds, float realElapseSeconds)
        {
            UpdateLoadAsset();
            UpdateLoadScene();
            UpdateUnloadScene();
        }

        public void InitResource(InitResourcesCompleteCallback initResourcesCompleteCallback)
        {
            initResourcesCompleteCallback?.Invoke();
        }

        private void UpdateLoadAsset()
        {
            if (_loadAssetInfos.Count <= 0)
                return;
            int count = 0;
            LinkedListNode<LoadAssetInfo> current = _loadAssetInfos.First;
            while (current != null && count < _loadAssetCountPerFrame)
            {
                LoadAssetInfo loadAssetInfo = current.Value;
                float elapseSeconds = (float) (DateTime.UtcNow - loadAssetInfo.StartTime).TotalSeconds;
                if (elapseSeconds >= loadAssetInfo.DelaySeconds)
                {
                    var path = loadAssetInfo.AssetName;
                    var t = loadAssetInfo.AssetType;
                    Object asset = GetCachedAsset(path);
                    if (asset == null)
                    {
                        //var resourcesPath = GetPathWithoutPrefixAndExtension(path);
                        //asset = Resources.Load(resourcesPath, t);
#if UNITY_EDITOR
                        asset = AssetDatabase.LoadAssetAtPath(path, t);
#endif

                        if (asset != null)
                        {
                            _cachedAssets.Add(path, asset);
                        }
                    }

                    if (asset != null)
                    {
                        var loadAssetSuccessCallback = loadAssetInfo.LoadAssetCallbacks.LoadAssetSuccessCallback;
                        loadAssetSuccessCallback?.Invoke(path, asset, elapseSeconds, loadAssetInfo.UserData);
                    }
                    else
                    {
                        var loadAssetFailureCallback = loadAssetInfo.LoadAssetCallbacks.LoadAssetFailureCallback;
                        loadAssetFailureCallback?.Invoke(path, "找不到", loadAssetInfo.UserData);
                    }

                    LinkedListNode<LoadAssetInfo> next = current.Next;
                    _loadAssetInfos.Remove(loadAssetInfo);
                    current = next;
                    count++;
                }
                else
                {
                    current = current.Next;
                }
            }
        }

        private void UpdateLoadScene()
        {
            if (_loadSceneInfos.Count <= 0)
                return;
            var current = _loadSceneInfos.First;
            while (current != null)
            {
                var loadSceneInfo = current.Value;
                if (loadSceneInfo.AsyncOperation.isDone)
                {
                    if (loadSceneInfo.AsyncOperation.allowSceneActivation)
                    {
                        if (loadSceneInfo.LoadSceneCallbacks.LoadSceneSuccessCallback != null)
                        {
                            loadSceneInfo.LoadSceneCallbacks.LoadSceneSuccessCallback(loadSceneInfo.AssetPath,
                                (float) (DateTime.UtcNow - loadSceneInfo.StartTime).TotalSeconds,
                                loadSceneInfo.UserData);
                        }
                    }
                    else
                    {
                        if (loadSceneInfo.LoadSceneCallbacks.LoadSceneFailureCallback != null)
                        {
                            loadSceneInfo.LoadSceneCallbacks.LoadSceneFailureCallback(loadSceneInfo.AssetPath,
                                loadSceneInfo.UserData);
                        }
                    }

                    var next = current.Next;
                    _loadSceneInfos.Remove(loadSceneInfo);
                    current = next;
                }
                else
                {
                    current = current.Next;
                }
            }
        }

        private void UpdateUnloadScene()
        {
            if (_unloadSceneInfos.Count <= 0)
                return;
            var current = _unloadSceneInfos.First;
            while (current != null)
            {
                var unloadSceneInfo = current.Value;
                if (unloadSceneInfo.AsyncOperation.isDone)
                {
                    if (unloadSceneInfo.AsyncOperation.allowSceneActivation)
                    {
                        if (unloadSceneInfo.UnloadSceneCallbacks.UnloadSceneSuccessCallback != null)
                        {
                            unloadSceneInfo.UnloadSceneCallbacks.UnloadSceneSuccessCallback(unloadSceneInfo.AssetPath,
                                unloadSceneInfo.UserData);
                        }
                    }
                    else
                    {
                        if (unloadSceneInfo.UnloadSceneCallbacks.UnloadSceneFailureCallback != null)
                        {
                            unloadSceneInfo.UnloadSceneCallbacks.UnloadSceneFailureCallback(unloadSceneInfo.AssetPath,
                                unloadSceneInfo.UserData);
                        }
                    }

                    var next = current.Next;
                    _unloadSceneInfos.Remove(unloadSceneInfo);
                    current = next;
                }
                else
                {
                    current = current.Next;
                }
            }
        }

        public void LoadAssetAsync<T>(string assetPath, LoadAssetCallbacks loadAssetCallbacks, object userData)
            where T : Object
        {
            //var delaySeconds = _minLoadDelayTime + Random.Range(_minLoadRandomDelayTime, _maxLoadRandomDelayTime);
            var delaySeconds = 0;
            var loadAssetInfo = new LoadAssetInfo(assetPath, typeof(T), 1, DateTime.UtcNow,
                delaySeconds, loadAssetCallbacks,
                userData);

            _loadAssetInfos.AddLast(loadAssetInfo);
        }

        public string GetPathWithoutPrefixAndExtension(string path)
        {
            string prefix = "Assets/Resources/";
            string extension = Path.GetExtension(path);
            int startIndex = prefix.Length;
            int endIndex = path.Length - extension.Length;
            int length = endIndex - startIndex;

            return path.Substring(startIndex, length);
        }

        public void UnloadAsset(string assetPath)
        {

        }

        private Object GetCachedAsset(string assetPath)
        {
            if (_cachedAssets.TryGetValue(assetPath, out var cachedAsset))
            {
                return cachedAsset;
            }

            return null;
        }

        public void LoadSceneAsync(string assetPath, LoadSceneCallbacks loadSceneCallbacks, object userData = null)
        {
            var asyncOperation = SceneManager.LoadSceneAsync(assetPath, LoadSceneMode.Additive);
            if (asyncOperation == null)
            {
                return;
            }

            var loadSceneInfo = new LoadSceneInfo(asyncOperation, assetPath, 1, DateTime.UtcNow, loadSceneCallbacks,
                userData);

            _loadSceneInfos.AddLast(loadSceneInfo);
        }

        public void UnloadScene(string assetPath, UnloadSceneCallbacks unloadAssetCallbacks, object userData = null)
        {
            var asyncOperation = SceneManager.UnloadSceneAsync(assetPath);
            if (asyncOperation == null)
            {
                return;
            }

            var unloadSceneInfo = new UnloadSceneInfo(asyncOperation, assetPath, unloadAssetCallbacks, userData);

            _unloadSceneInfos.AddLast(unloadSceneInfo);
        }

        public void LoadBinary(string assetPath, LoadBinaryCallbacks loadBinaryCallbacks, object userData = null)
        {
            throw new NotImplementedException();
        }

        public void UnloadBinary(string assetPath)
        {
            throw new NotImplementedException();
        }
    }
}
